package com.iiapk.contacts.ui.widget;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;

import android.content.ContentValues;
import android.content.Context;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.CursorAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;
import com.iiapk.contacts.FullContactsActivity;
import com.iiapk.contacts.R;

public class ContactItemListAdapter extends CursorAdapter implements
		SectionIndexer, PinnedHeaderListView.PinnedHeaderAdapter,
		OnScrollListener {

	private final static String TAG = "ContactItemListAdapter";

	private Context mCtx;
	private LayoutInflater mInflater;
	private ContactsSectionIndexer mIndexer;
	private List<ContentValues> mList = new ArrayList<ContentValues>();
	private BladeView mBladeView;

	private HashMap<String, Integer> alphaIndexer;
	private String[] sections;
	private String[] labelSections;
	private int[] counts;
	private int[] cursorOffsets;
	private int[] lineNums;
	private boolean[] startFlags;
    private int currentNum;
    private boolean startFlag;
	private int mPinnedHeaderBackgroundColor;
	private int cursorOffset;
	private int mSize;
	//private int mScrollState;
	private String headerStr;

	public ContactItemListAdapter(Context context) {
		super(context, null, false);
		mCtx = context;
		mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		mPinnedHeaderBackgroundColor = mCtx.getResources().getColor(R.color.pinned_header_background);
	}

	@Override
	public void changeCursor(Cursor cursor) {
		super.changeCursor(cursor);
		updateIndexer(cursor);
	}

	private void updateIndexer(Cursor cursor) {
        if (cursor == null) 
            return;
        
        if (cursor != null && cursor.getCount() > 0) {  
            cursor.moveToFirst();  
            mList.clear();
            mSize=0;
            for (int i = 0; i < cursor.getCount(); i++) {  
                cursor.moveToPosition(i);  
            	if (!cursor.isNull(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID))&&
            			!cursor.isNull(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME))) {
            		int _simPhoneIndicate1 = 0;
            		int _contactId = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
            		int _hasphone = (cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.HAS_PHONE_NUMBER)) != 0) ? 1: 0;
            		String _name = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
            		String _sort = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.SORT_KEY_PRIMARY));
            		ContentValues cv = new ContentValues();  
                    cv.put(ContactsContract.Contacts._ID, _contactId);  
                    cv.put("simPhoneIndicate1", _simPhoneIndicate1); 
                    cv.put(ContactsContract.Contacts.HAS_PHONE_NUMBER, _hasphone);  
                    cv.put(ContactsContract.Contacts.DISPLAY_NAME, _name);  
                    cv.put(ContactsContract.Contacts.SORT_KEY_PRIMARY, _sort);
                    mList.add(cv);  
            	}
            }  
        }
        
        this.alphaIndexer = new HashMap<String, Integer>();
		this.labelSections = new String[mList.size()];
		cursorOffsets = new int[mList.size()];
		int j=0;
		for (int i = 0; i < mList.size(); i++) {
			String name = getAlpha(mList.get(i).getAsString(
			ContactsContract.Contacts.SORT_KEY_PRIMARY));
			labelSections[i] = name;
			if (alphaIndexer.containsKey(name)) {
				alphaIndexer.put(name, alphaIndexer.get(name) + 1);
				int temp = j/3*3;
				j++;
				cursorOffsets[i]=temp>cursorOffsets[i-1]?temp:cursorOffsets[i-1];
			} else {
				alphaIndexer.put(name, 1);
				cursorOffsets[i]=i;
				j=i/3*3+1;
			}
		}
		
		Object[] objs = alphaIndexer.keySet().toArray();
		Arrays.sort(objs);
		this.sections = new String[objs.length];
		this.counts = new int[objs.length];
		for (int i = 0; i < objs.length; i++) {
			sections[i] = objs[i].toString();
			int _size = alphaIndexer.get(sections[i]);
			counts[i] = _size;
			_size = _size%3==0?_size/3:_size/3+1;
			mSize+=_size;
		}
		int[] realCounts = new int[counts.length];
        for (int index = 0; index < counts.length; index++){                    
            realCounts[index] = counts[index]/3;
            if ((counts[index]%3) != 0){
                realCounts[index]++;
            }
        }
        
        int position = 0;
        int lineCursorOffset = 0;
        int lineStart = 0;
        int lineEnd = realCounts[0] - 1;
        int lineCount = mSize;
        cursorOffsets = new int[lineCount];
        lineNums = new int[lineCount];
        startFlags = new boolean[lineCount];
        for (int sectionIndex = 0; sectionIndex < realCounts.length; sectionIndex++){
            position = lineStart;
            while (position < lineEnd){
                cursorOffsets[position] = lineCursorOffset;
                lineNums[position] = 3;
                lineCursorOffset += 3;
                startFlags[position] = false;
                position++;
            }
            startFlags[lineStart] = true;
            
            cursorOffsets[position] = lineCursorOffset;
            lineNums[position] = counts[sectionIndex]%3;
            if (lineNums[position] == 0){
                lineNums[position] = 3;
            }
            lineCursorOffset += lineNums[position];
                          
            if (sectionIndex != (realCounts.length - 1)){
                lineStart = lineEnd + 1;
                lineEnd = lineStart + realCounts[sectionIndex + 1] - 1;
            }                
        }
        
		mIndexer = new ContactsSectionIndexer(sections, realCounts);
        cursor.moveToFirst(); 
    }

	@Override
	public int getCount() {
		return mSize;
	}

	@Override
	public Object getItem(int position) {
		return mList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	private String getAlpha(String str) {
		if (str == null) {
			return "#";
		}
		if (str.trim().length() == 0) {
			return "#";
		}
		char c = str.trim().substring(0, 1).charAt(0);
		Pattern pattern = Pattern.compile("^[A-Za-z]+$");
		if (pattern.matcher(c + "").matches()) {
			return (c + "").toUpperCase();
		} else {
			return "#";
		}
	}

	/*private boolean isShowHeader(int position) {
		String currentStr = getAlpha(mList.get(position).getAsString(ContactsContract.Contacts.SORT_KEY_PRIMARY));
		String previewStr = (position - 1) >= 0 ? getAlpha(mList.get(position - 1)
				.getAsString(ContactsContract.Contacts.SORT_KEY_PRIMARY)) : " ";
		return !previewStr.equals(currentStr);
	}*/

	@Override
	public int getPositionForSection(int section) {
		if (mIndexer == null) {
			return -1;
		}
		int retVal = mIndexer.getPositionForSection(section);
		return retVal;
	}

	@Override
	public int getSectionForPosition(int position) {
		if (mIndexer == null) {
			return -1;
		}
		int retVal = mIndexer.getSectionForPosition(position);
		return retVal < 0 ? 0 : retVal;
	}

	@Override
	public Object[] getSections() {
		if (mIndexer == null) {
			return new String[] { " " };
		} else {
			return mIndexer.getSections();
		}
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View v = null;
		if (convertView == null) {
			v = newView(mCtx, super.getCursor(), parent);
		} else {
			v = convertView;
		}
		 cursorOffset = cursorOffsets[position];
         currentNum = lineNums[position];
         startFlag = startFlags[position];
         if (startFlag == true){
             final int section = getSectionForPosition(position);
             headerStr = (String)mIndexer.getSections()[section];
         }else{
             headerStr = null;
         }
		bindView(v, mCtx, getCursor());
		return v;
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
		return mInflater.inflate(R.layout.contacts_list_item_multiname, parent,false);
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor) {

		TextView nameView1 = (TextView) view.findViewById(R.id.itemtext1);
		TextView nameView2 = (TextView) view.findViewById(R.id.itemtext2);
		TextView nameView3 = (TextView) view.findViewById(R.id.itemtext3);
		ContentValues cv = null;
		cursor.moveToPosition(cursorOffset);
		
		if (startFlag == true){
            TextView labelView = (TextView)view.findViewById(R.id.itemheader);                
            labelView.setText(headerStr);
            labelView.setVisibility(View.VISIBLE);
        }else{
            TextView labelView = (TextView)view.findViewById(R.id.itemheader);                
            labelView.setVisibility(View.GONE);
        }
			
		cv = mList.get(cursor.getPosition());
		nameView1.setText(cv.getAsString(ContactsContract.Contacts.DISPLAY_NAME));
		nameView1.setOnClickListener((FullContactsActivity) mCtx);
		nameView1.setOnCreateContextMenuListener((FullContactsActivity) mCtx);
		nameView1.setTag(cv.get(ContactsContract.Contacts._ID));
		
		if (currentNum == 1) {
			nameView2.setText(null);
			nameView2.setTag(null);
			nameView2.setOnClickListener(null);
			nameView2.setOnCreateContextMenuListener(null);
			nameView3.setText(null);
			nameView3.setTag(null);
			nameView3.setOnClickListener(null);
			nameView3.setOnCreateContextMenuListener(null);
			return;
		} else {
			if(cursor.moveToNext()){
				cv = mList.get(cursor.getPosition());
				nameView2.setText(cv.getAsString(ContactsContract.Contacts.DISPLAY_NAME));
				nameView2.setOnClickListener((FullContactsActivity) mCtx);
				nameView2.setOnCreateContextMenuListener((FullContactsActivity) mCtx);
				nameView2.setTag(cv.get(ContactsContract.Contacts._ID));
			}
		}

		if (currentNum == 2) {
			nameView3.setText(null);
			nameView3.setTag(null);
			nameView3.setOnClickListener(null);
			nameView3.setOnCreateContextMenuListener(null);
			return;
		} else {
			if (cursor.moveToNext()) {
				cv = mList.get(cursor.getPosition());
				nameView3.setText(cv.getAsString(ContactsContract.Contacts.DISPLAY_NAME));
				nameView3.setOnClickListener((FullContactsActivity) mCtx);
				nameView3.setOnCreateContextMenuListener((FullContactsActivity) mCtx);
				nameView3.setTag(cv.get(ContactsContract.Contacts._ID));
			}
		}
	}

	/**
	 * Configures the pinned header by setting the appropriate text label and
	 * also adjusting color if necessary. The color needs to be adjusted when
	 * the pinned header is being pushed up from the view.
	 */
	public void configurePinnedHeader(View header, int position, int alpha) {
		PinnedHeaderCache cache = (PinnedHeaderCache) header.getTag();
		if (cache == null) {
			cache = new PinnedHeaderCache();
			cache.titleView = (TextView) header.findViewById(R.id.header_text);
			cache.textColor = cache.titleView.getTextColors();
			cache.background = header.getBackground();
			header.setTag(cache);
		}

		int section = getSectionForPosition(position);
		String title = (String) mIndexer.getSections()[section];
		cache.titleView.setText(title);
		Log.i(TAG, "cache.titleView.setText " + title);

		if (alpha == 256) {
			// Opaque: use the default background, and the original text color
			header.setBackgroundDrawable(cache.background);
			cache.titleView.setTextColor(cache.textColor);
		} else {
			// Faded: use a solid color approximation of the background, and
			// a translucent text color
			header.setBackgroundColor(Color.rgb(
                    Color.red(mPinnedHeaderBackgroundColor) * alpha / 255,
                    Color.green(mPinnedHeaderBackgroundColor) * alpha / 255,
                    Color.blue(mPinnedHeaderBackgroundColor) * alpha / 255));
			int textColor = cache.textColor.getDefaultColor();
			cache.titleView.setTextColor(Color.argb(alpha,
					Color.red(textColor), Color.green(textColor),
					Color.blue(textColor)));
		}
	}

	/**
	 * Computes the state of the pinned header. It can be invisible, fully
	 * visible or partially pushed up out of the view.
	 */
	public int getPinnedHeaderState(int position) {
		if (mIndexer == null || super.getCursor() == null
				|| super.getCursor().getCount() == 0) {
			Log.i(TAG, "getPinnedHeaderState PINNED_HEADER_GONE");
			return PINNED_HEADER_GONE;
		}
		// The header should get pushed up if the top item shown
		// is the last item in a section for a particular letter.
		int section = getSectionForPosition(position);
		int nextSectionPosition = getPositionForSection(section + 1);
		if (nextSectionPosition != -1 && position == nextSectionPosition - 1) {
			Log.i(TAG, "getPinnedHeaderState PINNED_HEADER_PUSHED_UP");
			return PINNED_HEADER_PUSHED_UP;
		}
		Log.i(TAG, "getPinnedHeaderState PINNED_HEADER_VISIBLE");
		return PINNED_HEADER_VISIBLE;
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		Log.i(TAG, "onScroll firstVisibleItem " + firstVisibleItem);
		if (view instanceof PinnedHeaderListView) {
			((PinnedHeaderListView) view).configureHeaderView(firstVisibleItem);
			if (mIndexer != null) {
				int section = getSectionForPosition(firstVisibleItem);
				if (mBladeView != null)
				mBladeView.setCurrentSection(section);
			}
		}
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//mScrollState = scrollState;
	}

	final static class PinnedHeaderCache {
		public TextView titleView;
		public ColorStateList textColor;
		public Drawable background;
	}

}
